/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cse.p2p.hash;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import com.cse.p2p.parser.*;
import com.cse.p2p.localfile.*;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import javax.swing.JProgressBar;

/**
 *
 * @author TuyetNgan
 */
public abstract class HashImplement {

	private static String convertToHex( byte[] data ) {
		StringBuffer buf = new StringBuffer();
		for ( int i = 0; i < data.length; i++ ) {
			int halfbyte = ( data[i] >>> 4 ) & 0x0F;
			int two_halfs = 0;
			do {
				if ( ( 0 <= halfbyte ) && ( halfbyte <= 9 ) ) {
					buf.append( ( char ) ( '0' + halfbyte ) );
				}
				else {
					buf.append( ( char ) ( 'a' + ( halfbyte - 10 ) ) );
				}
				halfbyte = data[i] & 0x0F;
			}
			while ( two_halfs++ < 1 );
		}
		return buf.toString();
	}

	private static String SHA1( byte[] input ) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		MessageDigest md;
		md = MessageDigest.getInstance( "SHA-1" );
		byte[] sha1hash = new byte[ 40 ]; // 40 byte hexa
		md.update( input, 0, input.length );
		sha1hash = md.digest();
		return convertToHex( sha1hash );
	}

	public static Boolean compareHash( String hash1, String hash2 ) {
		if ( hash1.equals( hash2 ) ) {
			return true;
		}
		else {
			return false;
		}
	}

	public static String getHashCodeForPieceID( int pieceID, Map hashMap ) {
		String result = null;
		for ( Object h : hashMap.keySet() ) {
			int i = ( Integer ) h;
			if ( i == pieceID ) {
				result = ( String ) hashMap.get( i );
				break;
			}
		}
		return result;
	}

	public static Map getHashMap( File file, int pieceSize, int pieceNumber )
			throws NoSuchAlgorithmException, UnsupportedEncodingException, FileNotFoundException, IOException {

		/** Hash and put each piece in MapHash 
		 * Use Autonumber to create PIECE_ID start with 1
		 */
		int id = 1;
		Map mapHashPiece = new HashMap();
		for ( int i = 0; i < pieceNumber; i++ ) {
			mapHashPiece.put( id++, getHash( LocalFile.getPiece( file.getAbsolutePath(),
																 i, pieceSize ) ) ); // getPiece in LocalFile
		}

		return mapHashPiece;
	}

	public static byte[] getBytesFromFile( File file ) throws IOException {
		FileInputStream is = new FileInputStream( file );

		// Get the size of the file
		long length = file.length();

		if ( length > Integer.MAX_VALUE ) {
			// File is too large
		}

		// Create the byte array to hold the data
		byte[] bytes = new byte[ ( int ) length ];

		// Read in the bytes
		int offset = 0;
		int numRead = 0;
		while ( offset < bytes.length
				&& ( numRead = is.read( bytes, offset, bytes.length - offset ) ) >= 0 ) {
			offset += numRead;
		}

		// Ensure all the bytes have been read in
		if ( offset < bytes.length ) {
			throw new IOException( "Could not completely read file " + file.getName() );
		}

		// Close the input stream and return bytes
		is.close();
		return bytes;
	}

	public static String getHashFile( File file, JProgressBar bar ) throws NoSuchAlgorithmException, UnsupportedEncodingException, IOException {
		MessageDigest md = MessageDigest.getInstance( "SHA-1");
		BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ) );
		byte[] buffer = new byte[ 256 * 1024 ];
		int read = 0;
		long done = 0;
		long total = file.length();
		while ( ( read = bis.read( buffer ) ) > 0 ) {
			md.update( buffer, 0, read );
			if (bar != null){
				done += read;
				bar.setValue( (int) ((double)done / total * 100));
				bar.repaint();
			}
		}
		byte[] mdbytes = md.digest();
		StringBuilder sb = new StringBuilder( "" );
		for ( int i = 0; i < mdbytes.length; i++ ) {
			sb.append( Integer.toString( ( mdbytes[i] & 0xff ) + 0x100, 16 ).substring( 1 ) );
		}
		return sb.toString();
	}

	public static String getHash( byte[] in ) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		return SHA1( in );
	}
}
